#region Copyright (c) 2000-2013 Developer Express Inc.
/*
{*******************************************************************}
{                                                                   }
{       Developer Express .NET Component Library                    }
{                                                                   }
{                                                                   }
{       Copyright (c) 2000-2013 Developer Express Inc.              }
{       ALL RIGHTS RESERVED                                         }
{                                                                   }
{   The entire contents of this file is protected by U.S. and       }
{   International Copyright Laws. Unauthorized reproduction,        }
{   reverse-engineering, and distribution of all or any portion of  }
{   the code contained in this file is strictly prohibited and may  }
{   result in severe civil and criminal penalties and will be       }
{   prosecuted to the maximum extent possible under the law.        }
{                                                                   }
{   RESTRICTIONS                                                    }
{                                                                   }
{   THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES           }
{   ARE CONFIDENTIAL AND PROPRIETARY TRADE                          }
{   SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS   }
{   LICENSED TO DISTRIBUTE THE PRODUCT AND ALL ACCOMPANYING .NET    }
{   CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY.                 }
{                                                                   }
{   THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED      }
{   FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE        }
{   COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE       }
{   AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT  }
{   AND PERMISSION FROM DEVELOPER EXPRESS INC.                      }
{                                                                   }
{   CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON       }
{   ADDITIONAL RESTRICTIONS.                                        }
{                                                                   }
{*******************************************************************}
*/
#endregion Copyright (c) 2000-2013 Developer Express Inc.

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
#if !SILVERLIGHT
using System.IO.Compression;
#if FORCE_USE_NATIVE_ENCODING || DXWINDOW
using DXEncoding = System.Text.Encoding;
#endif
#endif
#if DXWINDOW
namespace DevExpress.Internal.DXWindow {
#else
namespace DevExpress.Utils.Zip {
#endif
	#region ICheckSumCalculator<T>
	public interface ICheckSumCalculator<T> {
		T InitialCheckSumValue { get; }
		T UpdateCheckSum(T value, byte[] buffer, int offset, int count);
		T GetFinalCheckSum(T value);
	}
	#endregion
	#region Crc32CheckSumCalculator
	[CLSCompliant(false)]
	public class Crc32CheckSumCalculator : ICheckSumCalculator<uint> {
		static Crc32CheckSumCalculator instance;
		public static Crc32CheckSumCalculator Instance {
			get {
				if (instance == null)
					instance = new Crc32CheckSumCalculator();
				return instance;
			}
		}
		#region CheckSumCalculator<uint> Members
		public uint InitialCheckSumValue { get { return unchecked(0xFFFFFFFF); } }
		public uint UpdateCheckSum(uint value, byte[] buffer, int offset, int count) {
			return Crc32CheckSum.Update(value, buffer, offset, count);
		}
		public uint GetFinalCheckSum(uint value) {
			return unchecked(value ^ 0xFFFFFFFF);
		}
		#endregion
	}
	#endregion
	#region ByteCountCheckSumCalculator
	public class ByteCountCheckSumCalculator : ICheckSumCalculator<int> {
		static ByteCountCheckSumCalculator instance;
		public static ByteCountCheckSumCalculator Instance {
			get {
				if (instance == null)
					instance = new ByteCountCheckSumCalculator();
				return instance;
			}
		}
		#region CheckSumCalculator<uint> Members
		public int InitialCheckSumValue { get { return 0; } }
		public int UpdateCheckSum(int value, byte[] buffer, int offset, int count) {
			return value + count;
		}
		public int GetFinalCheckSum(int value) {
			return value;
		}
		#endregion
	}
	#endregion
	#region Crc32CheckSum
	[CLSCompliant(false)]
	public static class Crc32CheckSum {
		static uint[] table = CreateTable();
		static uint[] CreateTable() {
			uint[] result= new uint[256];
			for (uint n = 0; n < 256; n++) {
				uint c = n;
				for (int k = 0; k < 8; k++) {
					if ((c & 1) != 0)
						c = 0xedb88320 ^ (c >> 1);
					else
						c = c >> 1;
				}
				result[n] = c;
			}
			return result;
		}
		public static uint[] Table { get { return table; } }
		public static uint Update(uint checkSum, byte[] buffer, int offset, int count) {
			for (int i = offset, end = offset + count; i < end; i++)
				checkSum = (checkSum >> 8) ^ table[(checkSum ^ buffer[i]) & 0xFF];
			return checkSum;
		}
		public static uint Calculate(string str) {
			byte[] buffer = DXEncoding.ASCII.GetBytes(str);
			return Update(0xffffffff, buffer, 0, buffer.Length) ^ 0xffffffff;
		}
		public static uint Calculate(Stream stream) {
			long streamPos = stream.Position;
			const int bufferSize = 0x32000;
			byte[] buffer = new byte[bufferSize];
			int bytesRead = 0;
			uint crc = 0xffffffff;
			do {
				bytesRead = stream.Read(buffer, 0, bufferSize);
				crc = Update(crc, buffer, 0, bytesRead); 
			}
			while (bytesRead == bufferSize);
			stream.Position = streamPos;
			return ~crc;
		}
	}
	#endregion
	#region CheckSumStream<T>
	public class CheckSumStream<T> : Stream {
		readonly Stream stream;
		readonly ICheckSumCalculator<T> checkSumCalculator;
		T readCheckSum;
		T writeCheckSum;
		public CheckSumStream(Stream stream, ICheckSumCalculator<T> checkSumCalculator) {
			this.stream = stream;
			this.checkSumCalculator = checkSumCalculator;
			ResetCheckSum();
		}
		#region Properties
		public Stream Stream { get { return stream; } }
		public override bool CanRead { get { return Stream.CanRead; } }
		public override bool CanSeek { get { return Stream.CanSeek; } }
		public override bool CanWrite { get { return Stream.CanWrite; } }
		public override long Length { get { return Stream.Length; } }
		public override long Position { get { return Stream.Position; } set { Stream.Position = value; } }
		public T ReadCheckSum { get { return checkSumCalculator.GetFinalCheckSum(readCheckSum); } }
		public T WriteCheckSum { get { return checkSumCalculator.GetFinalCheckSum(writeCheckSum); } }
		#endregion
		public void ResetCheckSum() {
			readCheckSum = checkSumCalculator.InitialCheckSumValue;
			writeCheckSum = checkSumCalculator.InitialCheckSumValue;
		}
		public override void Flush() {
			Stream.Flush();
		}
		public override long Seek(long offset, SeekOrigin origin) {
			return Stream.Seek(offset, origin);
		}
		public override void SetLength(long value) {
			Stream.SetLength(value);
		}
		public override int Read(byte[] buffer, int offset, int count) {
			count = Stream.Read(buffer, offset, count);
			this.readCheckSum = checkSumCalculator.UpdateCheckSum(this.readCheckSum, buffer, offset, count);
			return count;
		}
		public override void Write(byte[] buffer, int offset, int count) {
			Stream.Write(buffer, offset, count);
			this.writeCheckSum = checkSumCalculator.UpdateCheckSum(this.writeCheckSum, buffer, offset, count);
		}
	}
	#endregion
	#region Crc32Stream
	[CLSCompliant(false)]
	public class Crc32Stream : CheckSumStream<uint> {
		public Crc32Stream(Stream stream)
			: base(stream, Crc32CheckSumCalculator.Instance) {
		}
	}
	#endregion
	#region ByteCountStream
	public class ByteCountStream : CheckSumStream<int> {
		public ByteCountStream(Stream stream)
			: base(stream, ByteCountCheckSumCalculator.Instance) {
		}
	}
	#endregion
	class CentralDirectoryEntry {
		uint crc32;
		public uint Crc32 { get { return crc32; } set { crc32 = value; } }
		uint compressedSize;
		public uint CompressedSize { get { return compressedSize; } set { compressedSize = value; } }
		uint uncompressedSize;
		public uint UncompressedSize { get { return uncompressedSize; } set { uncompressedSize = value; } }
		string fileName;
		public string FileName { get { return fileName; } set { fileName = value; } }
		uint msDosDateTime;
		public uint MsDosDateTime { get { return msDosDateTime; } set { msDosDateTime = value; } }
		uint relativeOffset;
		public uint RelativeOffset { get { return relativeOffset; } set { relativeOffset = value; } }
	}
	#region CompressionMethod
	public enum CompressionMethod {
		Store = 0,
		Shrunke = 1,
		Reduce1 = 2,
		Reduce2 = 3,
		Reduce3 = 4,
		Reduce4 = 5,
		Implode = 6,
		TokenizingCompression = 7,
		Deflate = 8,
		Deflate64 = 9,
		PkWareImplode = 10,
		BZip2 = 12,
		LZMA = 14,
		IbmTerse = 18,
		LZ77 = 19,
		PPMd11 = 98
	}
	#endregion
	#region ZipSignatures
	public enum ZipSignatures {
		FileRecord = 0x04034b50, 
		DataDescriptorRecord = 0x08074b50, 
		MultiVolumeArchiveRecord = 0x08074b50, 
		ArchveExtraDataRecord = 0x08064b50, 
		FileEntryRecord = 0x02014b50, 
		DigitalSignatureRecord = 0x05054b50, 
		EndOfCentralDirSignature = 0x06054b50, 
	}
	#endregion
	#region ZipArchive
	public class ZipArchive : IDisposable {
		readonly Stream zipStream;
		readonly BinaryWriter writer;
		readonly List<CentralDirectoryEntry> centralDirectory;
		readonly bool requireDisposeForStream;
		public ZipArchive(string zipFileName)
			: this(new FileStream(zipFileName, FileMode.Create, FileAccess.Write)) {
			requireDisposeForStream = true;
		}
		public ZipArchive(Stream stream) {
			zipStream = stream;
			writer = new BinaryWriter(zipStream);
			centralDirectory = new List<CentralDirectoryEntry>();
		}
		List<CentralDirectoryEntry> CentralDirectory { get { return centralDirectory; } }
		BinaryWriter Writer { get { return writer; } }
		Stream ZipStream { get { return zipStream; } }
		Encoding UTF8Encoding { get { return Encoding.UTF8; } }
		Encoding ASCIIEncoding { get { return DXEncoding.ASCII; } }
		uint ToMsDosDateTime(DateTime dateTime) {
			uint num = 0;
			num |= (uint)((dateTime.Second / 2) & 0x1f);
			num |= (uint)((dateTime.Minute & 0x3f) << 5);
			num |= (uint)((dateTime.Hour & 0x1f) << 11);
			num |= (uint)((dateTime.Day & 0x1f) << 0x10);
			num |= (uint)((dateTime.Month & 15) << 0x15);
			return (num | ((uint)(((dateTime.Year - 0x7bc) & 0x7f) << 0x19)));
		}
		void WriteCentralDirectory() {
			long centralDirectoryStartPosition = ZipStream.Position;
			for (int i = 0; i < CentralDirectory.Count; i++) {
				CentralDirectoryEntry dirEntry = CentralDirectory[i];
				Writer.Write((uint)ZipSignatures.FileEntryRecord);
				Writer.Write((short)0x14);	
				Writer.Write((short)0x14);	
				Writer.Write((short)2);		
				Writer.Write((short)GetDeflateStreamCompressionMethod());		
				Writer.Write(dirEntry.MsDosDateTime);	
				Writer.Write(dirEntry.Crc32);			
				Writer.Write(dirEntry.CompressedSize);
				Writer.Write(dirEntry.UncompressedSize);
				Writer.Write((short)dirEntry.FileName.Length);
				Writer.Write((short)0);		
				Writer.Write((short)0);		
				Writer.Write((short)0);		
				Writer.Write((short)0);		
				Writer.Write((uint)0);		
				Writer.Write(dirEntry.RelativeOffset);		
				Writer.Write(ASCIIEncoding.GetBytes(dirEntry.FileName));
			}
			long centralDirectoryEndPosition = ZipStream.Position;
			Writer.Write((uint)ZipSignatures.EndOfCentralDirSignature);
			Writer.Write((short)0);			
			Writer.Write((short)0);			
			Writer.Write((short)CentralDirectory.Count);			
			Writer.Write((short)CentralDirectory.Count);			
			Writer.Write((uint)(centralDirectoryEndPosition - centralDirectoryStartPosition));			
			Writer.Write((uint)centralDirectoryStartPosition);	
			Writer.Write((short)0);
		}
		protected internal virtual Stream CreateDeflateStream(Stream stream) {
			return new DeflateStream(stream, CompressionMode.Compress, true);
		}
		protected internal CompressionMethod GetDeflateStreamCompressionMethod() {
			return CompressionMethod.Deflate; 
		}
		public void Add(string fileName) {
			using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
				Add(Path.GetFileName(fileName), File.GetLastWriteTime(fileName), stream);
		}
		public void AddCompressed(string name, DateTime fileTime, CompressedStream compressedStream) {
			Stream stream = compressedStream.Stream;
			name = name.Replace('\\', '/');
			CentralDirectoryEntry dirEntry = new CentralDirectoryEntry();
			dirEntry.MsDosDateTime = ToMsDosDateTime(fileTime);
			dirEntry.Crc32 = (uint)compressedStream.Crc32;
			dirEntry.CompressedSize = (uint)(stream.Length - stream.Position);
			dirEntry.FileName = name;
			dirEntry.UncompressedSize = (uint)compressedStream.UncompressedSize;
			dirEntry.RelativeOffset = (uint)ZipStream.Position;
			WriteDirectoryEntry(dirEntry);
			CopyStream(stream, ZipStream);
			CentralDirectory.Add(dirEntry);
			ZipStream.Position = ZipStream.Length;
		}
		public void Add(string name, DateTime fileTime, Stream stream) {
			name = name.Replace('\\', '/');
			CentralDirectoryEntry dirEntry = new CentralDirectoryEntry();
			dirEntry.MsDosDateTime = ToMsDosDateTime(fileTime);
			dirEntry.FileName = name;
			dirEntry.UncompressedSize = (uint)(stream.Length - stream.Position);
			dirEntry.RelativeOffset = (uint)ZipStream.Position;
			long crc32Position = WriteDirectoryEntry(dirEntry);
			long compressedDataStartPosition = ZipStream.Position;
			Crc32Stream crc32Stream = new Crc32Stream(stream);
			using (Stream compressStream = CreateDeflateStream(ZipStream)) {
				CopyStream(crc32Stream, compressStream);
			}
			dirEntry.Crc32 = crc32Stream.ReadCheckSum;
			dirEntry.CompressedSize = (uint)(ZipStream.Position - compressedDataStartPosition);
			ZipStream.Position = crc32Position;
			Writer.Write(dirEntry.Crc32);
			Writer.Write(dirEntry.CompressedSize);
			CentralDirectory.Add(dirEntry);
			ZipStream.Position = ZipStream.Length;
		}
		void CopyStream(Stream sourceStream, Stream targetStream) {
			const int bufferSize = 32768;
			byte[] buffer = new byte[bufferSize];
			int bytesRead = 0;
			do {
				bytesRead = sourceStream.Read(buffer, 0, bufferSize);
				targetStream.Write(buffer, 0, bytesRead);
			}
			while (bytesRead == bufferSize);
		}
		long WriteDirectoryEntry(CentralDirectoryEntry dirEntry) {
			Writer.Write((uint)ZipSignatures.FileRecord);
			Writer.Write((short)0x14); 
			Writer.Write((short)2); 
			Writer.Write((short)GetDeflateStreamCompressionMethod());
			Writer.Write(dirEntry.MsDosDateTime); 
			long crc32Position = ZipStream.Position;
			Writer.Write(dirEntry.Crc32); 
			Writer.Write(dirEntry.CompressedSize); 
			Writer.Write(dirEntry.UncompressedSize);
			Writer.Write((short)dirEntry.FileName.Length);
			Writer.Write((short)0);
			Writer.Write(ASCIIEncoding.GetBytes(dirEntry.FileName));
			return crc32Position;
		}
		public void Add(string fileName, DateTime fileTime, string content) {
			Add(fileName, fileTime, UTF8Encoding.GetBytes(content));
		}
		public void Add(string fileName, DateTime fileTime, byte[] content) {
			using (MemoryStream stream = new MemoryStream(content, false))
				Add(fileName, fileTime, stream);
		}
		public void Add(string fileName, DateTime fileTime, byte[] content, int index, int count) {
			using (MemoryStream stream = new MemoryStream(content, index, count, false))
				Add(fileName, fileTime, stream);
		}
		public static ZipFileCollection Open(Stream stream) {
			return Open(stream, DXEncoding.Default);
		}
		public static ZipFileCollection Open(Stream stream, Encoding fileNameEncoding) {
			ZipFileCollection result = new ZipFileCollection();
			BinaryReader reader = new BinaryReader(stream);
			for (; ; ) {
				ZipSignatures signature = (ZipSignatures)reader.ReadInt32();
				switch (signature) {
					case ZipSignatures.FileRecord:
						result.Add(ProcessZipFile(stream, fileNameEncoding));
						break;
					default:
						return result;
				}
			}
		}
		protected internal static ZipFile ProcessZipFile(Stream stream, Encoding fileNameEncoding) {
			ZipFile zipFile = new ZipFile();
			zipFile.DefaultEncoding = fileNameEncoding;
			zipFile.Prepare(stream);
			return zipFile;
		}
		#region IDisposable Members
		void IDisposable.Dispose() {
			WriteCentralDirectory();
			if (zipStream != null) {
				if (requireDisposeForStream)
					zipStream.Dispose();
				else
					zipStream.Flush();
			}
		}
		#endregion
	}
	#endregion
	#region CompressedStream
	public class CompressedStream {
		int crc32;
		int uncompressedSize;
		Stream stream;
		public int Crc32 { get { return crc32; } set { crc32 = value; } }
		public int UncompressedSize { get { return uncompressedSize; } set { uncompressedSize = value; } }
		public Stream Stream { get { return stream; } set { stream = value; } }
	}
	#endregion
	#region ZipFlags
	[Flags]
	public enum ZipFlags {
		Encrypted = 0x0001,
		ImplodeUse8kSlidingDictionary = 0x0002,
		ImplodeUse4kSlidingDictionary = 0x0000,
		ImplodeUse3ShannonFanoTrees = 0x0004,
		ImplodeUse2ShannonFanoTrees = 0x0000,
		DeflateNormalCompression = 0x0000,
		DeflateMaximumCompression = 0x0002,
		DeflateFastCompression = 0x0004,
		DeflateSuperFastCompression = 0x0007,
		LZMAEOSIndicatesEndOfStream = 0x0001,
		UseDataFromDataDescriptor = 0x0008,
		ArchiveContainsCompressedPatchedData = 0x0020,
		StrongEncryption = 0x0040,
		Unused1 = 0x0080,
		Unused2 = 0x0100,
		Unused3 = 0x0200,
		Unused4 = 0x0400,
		EFS = 0x0800,
		LocalHeaderDataMasked = 0x2000,
	}
	#endregion
	#region ZipFileCollection
	public class ZipFileCollection : List<ZipFile> {
	}
	#endregion
	#region ZipFile
	public class ZipFile {
		#region Fields
		Int16 versionToExtract;
		ZipFlags generalPurposeBitFlag;
		CompressionMethod compressionMethod;
		Int16 fileLastModificationTime;
		Int16 fileLastModificationDate;
		Int32 crc32;
		long compressedSize;
		long uncompressedSize;
		string fileName;
		Stream fileDataStream;
		BinaryReader reader;
		Encoding fileNameEncoding = DXEncoding.Default;
		#endregion
		#region Properties
		public long UncompressedSize { get { return uncompressedSize; } }
		public Stream FileDataStream { get { return fileDataStream; } }
		public string FileName { get { return fileName; } }
		internal Encoding DefaultEncoding {
			get { return fileNameEncoding; }
			set {
				if (value == null)
					value = DXEncoding.Default;
				fileNameEncoding = value;
			}
		}
		#endregion
		protected internal void Prepare(Stream stream) {
			reader = new BinaryReader(stream);
			versionToExtract = reader.ReadInt16();
			generalPurposeBitFlag = (ZipFlags)reader.ReadInt16();
			compressionMethod = (CompressionMethod)reader.ReadInt16();
			fileLastModificationTime = reader.ReadInt16();
			fileLastModificationDate = reader.ReadInt16();
			crc32 = reader.ReadInt32();
			compressedSize = reader.ReadInt32();
			uncompressedSize = reader.ReadInt32();
			Int16 fileNameLength = reader.ReadInt16();
			Int16 extraFieldLength = reader.ReadInt16();
			byte[] fileNameBytes = reader.ReadBytes(fileNameLength);
			fileName = DefaultEncoding.GetString(fileNameBytes, 0, fileNameBytes.Length);
			reader.ReadBytes(extraFieldLength); 
			fileDataStream = CreateDecompressionStream(stream, compressionMethod, uncompressedSize);
			stream.Seek(compressedSize, SeekOrigin.Current);
			if ((generalPurposeBitFlag & ZipFlags.UseDataFromDataDescriptor) != 0) {
				SeekToDataDescriptorData(stream, compressedSize);
				crc32 = reader.ReadInt32();
				compressedSize = reader.ReadInt32();
				uncompressedSize = reader.ReadInt32();
			}
		}
		protected internal virtual void SeekToDataDescriptorData(Stream stream, long compressedSize) {
			if (compressedSize != 0) {
				ZipSignatures signature = (ZipSignatures)reader.ReadInt32();
				if (signature != ZipSignatures.DataDescriptorRecord)
					stream.Seek(-sizeof(Int32), SeekOrigin.Current);
			}
			else {
				byte[] pattern = new byte[] { (byte)'P', (byte)'K', 0x07, 0x08 };
				byte[] bytes = new byte[7]; 
				stream.Read(bytes, 0, 7);
				for (; ; ) {
					int index = SearchForPattern(bytes, pattern);
					if (index >= 0) {
						stream.Seek(index - 3 , SeekOrigin.Current);
						break;
					}
					bytes[0] = bytes[4];
					bytes[1] = bytes[5];
					bytes[2] = bytes[6];
					if (stream.Read(bytes, 3, 4) == 0)
						break;
				}
			}
		}
		protected internal int SearchForPattern(byte[] bytes, byte[] pattern) {
			int bufferLength = bytes.Length;
			int patternLength = pattern.Length;
			if (bufferLength < patternLength)
				return -1;
			int patternIndex = 0;
			for (int i = 0; i < bufferLength; i++) {
				if (bytes[i] == pattern[patternIndex]) {
					patternIndex++;
					if (patternIndex >= patternLength)
						return i - patternLength + 1;
				}
				else {
					if (patternIndex > 0)
						i--;
					patternIndex = 0;
				}
			}
			return -1;
		}
		protected internal virtual Stream CreateDecompressionStream(Stream sourceStream, CompressionMethod compressionMethod, long uncompressedSize) {
			if (compressionMethod == CompressionMethod.Deflate)
				return new DeflateStream(new FixedOffsetSequentialReadOnlyStream(sourceStream, -1), CompressionMode.Decompress, true);
			return new FixedOffsetSequentialReadOnlyStream(sourceStream, uncompressedSize);
		}
	}
	#endregion
	#region FixedOffsetSequentialReadOnlyStream
	public class FixedOffsetSequentialReadOnlyStream : Stream {
		#region Fields
		readonly Stream baseStream;
		readonly long basePosition;
		readonly long length;
		long position;
		#endregion
		public FixedOffsetSequentialReadOnlyStream(Stream baseStream, long length) {
			this.baseStream = baseStream;
			this.basePosition = baseStream.Position;
			this.length = length;
		}
		#region Properties
		public Stream BaseStream { get { return baseStream; } }
		public override bool CanRead { get { return BaseStream.CanRead; } }
		public override bool CanSeek { get { return false; } }
		public override bool CanWrite { get { return false; } }
		public override long Length {
			get {
				if (length < 0)
					throw new NotSupportedException();
				return length;
			}
		}
		public override long Position {
			get { return position; }
			set {
				throw new NotSupportedException();
			}
		}
		#endregion
		protected internal virtual void ValidateBaseStreamPosition() {
			if (BaseStream.Position != basePosition + position)
				BaseStream.Seek(basePosition + position - BaseStream.Position, SeekOrigin.Current);
		}
		public override int Read(byte[] buffer, int offset, int count) {
			ValidateBaseStreamPosition();
			if (length >= 0) {
				if (position + count > length)
					count = (int)(length - position);
			}
			int actualByteCount = BaseStream.Read(buffer, offset, count);
			position += actualByteCount;
			return actualByteCount;
		}
		public override long Seek(long offset, SeekOrigin origin) {
			throw new NotSupportedException();
		}
		public override void SetLength(long value) {
			throw new NotSupportedException();
		}
		public override void Write(byte[] buffer, int offset, int count) {
			throw new NotSupportedException();
		}
		public override void Flush() {
			throw new NotSupportedException();
		}
	}
	#endregion
}
